﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media.Animation;

namespace MyCalManager.Helper
{
    public class Reveal : Decorator
    {
        // Fields
        public static readonly DependencyProperty AnimationProgressProperty = DependencyProperty.Register("AnimationProgress", typeof(double), typeof(MyCalManager.Helper.Reveal), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure, null, new CoerceValueCallback(MyCalManager.Helper.Reveal.OnCoerceAnimationProgress)));
        public static readonly DependencyProperty DurationProperty = DependencyProperty.Register("Duration", typeof(double), typeof(MyCalManager.Helper.Reveal), new UIPropertyMetadata(250.0));
        public static readonly DependencyProperty HorizontalRevealProperty = DependencyProperty.Register("HorizontalReveal", typeof(HorizontalRevealMode), typeof(MyCalManager.Helper.Reveal), new UIPropertyMetadata(HorizontalRevealMode.None));
        public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register("IsExpanded", typeof(bool), typeof(MyCalManager.Helper.Reveal), new UIPropertyMetadata(false, new PropertyChangedCallback(MyCalManager.Helper.Reveal.OnIsExpandedChanged)));
        public static readonly DependencyProperty VerticalRevealProperty = DependencyProperty.Register("VerticalReveal", typeof(VerticalRevealMode), typeof(MyCalManager.Helper.Reveal), new UIPropertyMetadata(VerticalRevealMode.FromTopToBottom));

        // Methods
        static Reveal()
        {
            UIElement.ClipToBoundsProperty.OverrideMetadata(typeof(MyCalManager.Helper.Reveal), new FrameworkPropertyMetadata(true));
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            UIElement child = this.Child;
            if (child != null)
            {
                double animationProgress = this.AnimationProgress;
                HorizontalRevealMode horizontalReveal = this.HorizontalReveal;
                VerticalRevealMode verticalReveal = this.VerticalReveal;
                double width = child.DesiredSize.Width;
                double height = child.DesiredSize.Height;
                double x = CalculateLeft(width, animationProgress, horizontalReveal);
                double y = CalculateTop(height, animationProgress, verticalReveal);
                child.Arrange(new Rect(x, y, width, height));
                width = child.RenderSize.Width;
                height = child.RenderSize.Height;
                double num6 = CalculateWidth(width, animationProgress, horizontalReveal);
                return new Size(num6, CalculateHeight(height, animationProgress, verticalReveal));
            }
            return new Size();
        }

        private static double CalculateHeight(double originalHeight, double percent, VerticalRevealMode reveal)
        {
            if (reveal == VerticalRevealMode.None)
            {
                return originalHeight;
            }
            return (originalHeight * percent);
        }

        private static double CalculateLeft(double width, double percent, HorizontalRevealMode reveal)
        {
            if (reveal == HorizontalRevealMode.FromRightToLeft)
            {
                return ((percent - 1.0) * width);
            }
            if (reveal == HorizontalRevealMode.FromCenterToEdge)
            {
                return (((percent - 1.0) * width) * 0.5);
            }
            return 0.0;
        }

        private static double CalculateTop(double height, double percent, VerticalRevealMode reveal)
        {
            if (reveal == VerticalRevealMode.FromBottomToTop)
            {
                return ((percent - 1.0) * height);
            }
            if (reveal == VerticalRevealMode.FromCenterToEdge)
            {
                return (((percent - 1.0) * height) * 0.5);
            }
            return 0.0;
        }

        private static double CalculateWidth(double originalWidth, double percent, HorizontalRevealMode reveal)
        {
            if (reveal == HorizontalRevealMode.None)
            {
                return originalWidth;
            }
            return (originalWidth * percent);
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            UIElement child = this.Child;
            if (child != null)
            {
                child.Measure(availableSize);
                double animationProgress = this.AnimationProgress;
                double width = CalculateWidth(child.DesiredSize.Width, animationProgress, this.HorizontalReveal);
                return new Size(width, CalculateHeight(child.DesiredSize.Height, animationProgress, this.VerticalReveal));
            }
            return new Size();
        }

        private static object OnCoerceAnimationProgress(DependencyObject d, object baseValue)
        {
            double num = (double)baseValue;
            if (num < 0.0)
            {
                return 0.0;
            }
            if (num > 1.0)
            {
                return 1.0;
            }
            return baseValue;
        }

        private static void OnIsExpandedChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            ((MyCalManager.Helper.Reveal)sender).SetupAnimation((bool)e.NewValue);
        }

        private void SetupAnimation(bool isExpanded)
        {
            double animationProgress = this.AnimationProgress;
            if (isExpanded)
            {
                animationProgress = 1.0 - animationProgress;
            }
            DoubleAnimation animation = new DoubleAnimation
            {
                To = new double?(isExpanded ? 1.0 : 0.0),
                Duration = TimeSpan.FromMilliseconds(this.Duration * animationProgress),
                FillBehavior = FillBehavior.HoldEnd
            };
            base.BeginAnimation(AnimationProgressProperty, animation);
        }

        // Properties
        public double AnimationProgress
        {
            get
            {
                return (double)base.GetValue(AnimationProgressProperty);
            }
            set
            {
                base.SetValue(AnimationProgressProperty, value);
            }
        }

        public double Duration
        {
            get
            {
                return (double)base.GetValue(DurationProperty);
            }
            set
            {
                base.SetValue(DurationProperty, value);
            }
        }

        public HorizontalRevealMode HorizontalReveal
        {
            get
            {
                return (HorizontalRevealMode)base.GetValue(HorizontalRevealProperty);
            }
            set
            {
                base.SetValue(HorizontalRevealProperty, value);
            }
        }

        public bool IsExpanded
        {
            get
            {
                return (bool)base.GetValue(IsExpandedProperty);
            }
            set
            {
                base.SetValue(IsExpandedProperty, value);
            }
        }

        public VerticalRevealMode VerticalReveal
        {
            get
            {
                return (VerticalRevealMode)base.GetValue(VerticalRevealProperty);
            }
            set
            {
                base.SetValue(VerticalRevealProperty, value);
            }
        }
    }


}
